using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace RabbitTraceability.Api.Filters
{
    /// <summary>
    /// 日志记录操作过滤器
    /// </summary>
    public class LoggingActionFilter : IActionFilter
    {
        private readonly ILogger<LoggingActionFilter> _logger;
        private const string StopwatchKey = "ActionStopwatch";
        private static readonly string[] SensitiveProperties = { "password", "pwd", "secret", "token", "apikey", "api_key", "accesstoken", "access_token" };

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        public LoggingActionFilter(ILogger<LoggingActionFilter> logger)
        {
            _logger = logger;
        }

        /// <summary>
        /// 在操作执行前调用
        /// </summary>
        /// <param name="context">操作执行上下文</param>
        public void OnActionExecuting(ActionExecutingContext context)
        {
            // 为每个请求创建一个新的计时器并存储在HttpContext中
            var stopwatch = new Stopwatch();
            stopwatch.Start();
            context.HttpContext.Items[StopwatchKey] = stopwatch;

            // 获取请求信息
            var request = context.HttpContext.Request;
            var requestMethod = request.Method;
            var requestPath = request.Path;
            var requestQueryString = request.QueryString;
            var requestContentType = request.ContentType;
            var controller = context.RouteData.Values["controller"];
            var action = context.RouteData.Values["action"];

            // 构建请求信息日志
            var logBuilder = new StringBuilder();
            logBuilder.AppendLine($"请求开始: {requestMethod} {requestPath}{requestQueryString}");
            logBuilder.AppendLine($"Controller: {controller}, Action: {action}");
            logBuilder.AppendLine($"Content-Type: {requestContentType}");

            // 记录请求参数（过滤敏感信息）
            if (context.ActionArguments.Count > 0)
            {
                logBuilder.AppendLine("请求参数:");
                foreach (var arg in context.ActionArguments)
                {
                    string argValue;
                    if (IsSensitiveProperty(arg.Key))
                    {
                        argValue = "******";
                    }
                    else if (arg.Value == null)
                    {
                        argValue = "null";
                    }
                    else if (IsSimpleType(arg.Value.GetType()))
                    {
                        argValue = arg.Value.ToString();
                    }
                    else
                    {
                        try
                        {
                            // 对于复杂对象，使用JSON序列化并过滤敏感字段
                            var jsonOptions = new JsonSerializerOptions
                            {
                                WriteIndented = true,
                                MaxDepth = 3 // 限制序列化深度
                            };
                            var json = JsonSerializer.Serialize(arg.Value, jsonOptions);
                            argValue = FilterSensitiveData(json);
                        }
                        catch
                        {
                            argValue = "[无法序列化的复杂对象]";
                        }
                    }

                    // 限制参数值的长度
                    if (argValue.Length > 500)
                    {
                        argValue = argValue.Substring(0, 500) + "... [已截断]";
                    }

                    logBuilder.AppendLine($"  {arg.Key}: {argValue}");
                }
            }

            // 记录请求信息
            _logger.LogInformation(logBuilder.ToString());
        }

        /// <summary>
        /// 在操作执行后调用
        /// </summary>
        /// <param name="context">操作执行上下文</param>
        public void OnActionExecuted(ActionExecutedContext context)
        {
            // 从HttpContext中获取计时器
            if (!context.HttpContext.Items.TryGetValue(StopwatchKey, out var stopwatchObj) || !(stopwatchObj is Stopwatch stopwatch))
            {
                stopwatch = new Stopwatch();
            }
            stopwatch.Stop();

            // 获取请求信息
            var request = context.HttpContext.Request;
            var requestMethod = request.Method;
            var requestPath = request.Path;
            var controller = context.RouteData.Values["controller"];
            var action = context.RouteData.Values["action"];

            // 构建响应信息日志
            var logBuilder = new StringBuilder();
            logBuilder.AppendLine($"请求完成: {requestMethod} {requestPath}");
            logBuilder.AppendLine($"Controller: {controller}, Action: {action}");
            logBuilder.AppendLine($"执行时间: {stopwatch.ElapsedMilliseconds}ms");

            // 记录状态码
            var statusCode = context.HttpContext.Response.StatusCode;
            logBuilder.AppendLine($"状态码: {statusCode}");

            // 记录响应结果（如果可用）
            if (context.Result != null)
            {
                string resultContent = "未知响应类型";

                if (context.Result is ObjectResult objectResult)
                {
                    try
                    {
                        if (objectResult.Value != null)
                        {
                            if (IsSimpleType(objectResult.Value.GetType()))
                            {
                                resultContent = objectResult.Value.ToString();
                            }
                            else
                            {
                                var jsonOptions = new JsonSerializerOptions
                                {
                                    WriteIndented = true,
                                    MaxDepth = 3 // 限制序列化深度
                                };
                                resultContent = JsonSerializer.Serialize(objectResult.Value, jsonOptions);
                            }

                            // 限制响应内容的长度
                            if (resultContent.Length > 1000)
                            {
                                resultContent = resultContent.Substring(0, 1000) + "... [已截断]";
                            }
                        }
                        else
                        {
                            resultContent = "null";
                        }
                    }
                    catch
                    {
                        resultContent = "[无法序列化的响应内容]";
                    }
                }
                else if (context.Result is FileResult)
                {
                    resultContent = "[文件内容]";
                }
                else if (context.Result is ContentResult contentResult)
                {
                    resultContent = contentResult.Content;
                    if (resultContent != null && resultContent.Length > 1000)
                    {
                        resultContent = resultContent.Substring(0, 1000) + "... [已截断]";
                    }
                }

                logBuilder.AppendLine($"响应内容: {resultContent}");
            }

            // 如果有异常，记录异常信息
            if (context.Exception != null && !context.ExceptionHandled)
            {
                logBuilder.AppendLine($"异常: {context.Exception.Message}");
                logBuilder.AppendLine($"异常堆栈: {context.Exception.StackTrace}");
                _logger.LogError(context.Exception, logBuilder.ToString());
            }
            else
            {
                _logger.LogInformation(logBuilder.ToString());
            }
        }

        /// <summary>
        /// 检查是否为敏感属性
        /// </summary>
        /// <param name="propertyName">属性名</param>
        /// <returns>是否为敏感属性</returns>
        private bool IsSensitiveProperty(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName))
                return false;

            string lowerName = propertyName.ToLower();
            foreach (var sensitiveProperty in SensitiveProperties)
            {
                if (lowerName.Contains(sensitiveProperty))
                    return true;
            }
            return false;
        }

        /// <summary>
        /// 过滤敏感数据
        /// </summary>
        /// <param name="json">JSON字符串</param>
        /// <returns>过滤后的JSON字符串</returns>
        private string FilterSensitiveData(string json)
        {
            if (string.IsNullOrEmpty(json))
                return json;

            foreach (var sensitiveProperty in SensitiveProperties)
            {
                // 使用正则表达式匹配JSON中的敏感字段并替换值
                json = System.Text.RegularExpressions.Regex.Replace(
                    json,
                    $"\"{sensitiveProperty}\"\\s*:\\s*\"[^\"]*\"",
                    $"\"{sensitiveProperty}\": \"******\"",
                    System.Text.RegularExpressions.RegexOptions.IgnoreCase);
            }
            return json;
        }

        /// <summary>
        /// 判断是否为简单类型
        /// </summary>
        /// <param name="type">类型</param>
        /// <returns>是否为简单类型</returns>
        private bool IsSimpleType(Type type)
        {
            return type.IsPrimitive || 
                   type == typeof(string) || 
                   type == typeof(decimal) || 
                   type == typeof(DateTime) || 
                   type == typeof(Guid) || 
                   type == typeof(TimeSpan) ||
                   type.IsEnum;
        }
    }
} 